package com.xzy.dao.impl;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

public abstract class BaseDao<T> {
    // 该泛型作用是让子类获取该泛型对象进而获得该泛型的真实类型
    // 目的是获取t.class对象用来创建实例(查询时不需要再传递t.class作为new对象的参数了)
    //	抽象类不能实例化，也就是不能使用 new 关键字创建对象。
    private  Class<T> clazz = null;
    //该初始化代码块类似一个功能性代码:作用是获取父类的泛型
    {
        Type genericSuperclass = this.getClass().getGenericSuperclass();//获取当前类的带泛型的父类
        //this不指baseDAO对象,abstract是不能实例化的 this指的是调用该构造器的对象
        ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass; //强转为一个参数化类型
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();//获取该参数化类型的参数(泛型参数)
        clazz = (Class) actualTypeArguments[0];
    }


    private QueryRunner queryRunner = new QueryRunner();

    /**
     * 用于执行Insert updata delete语句
     * @return 返回影响行数若返回-1则执行失败
     */
    public int update(Connection conn, String sql, Object... args){
        try {
            //实例化bean对象时bean变量名应和数据库中相同 否则应该在查询时使用别名
            return queryRunner.update(conn,sql,args);
        } catch (SQLException throwables) {
            throw new RuntimeException(throwables);//此时将异常抛出(为了在事务操作出现异常时,能够检查到异常并同一回滚)
        }

        //此时不关闭conn 因为可能有事务存在  应该在事务执行完毕后统一关闭连接
    }

    /**
     * 单个查询
     * @param conn
     * @param sql
     * @param args
     * @return 返回查询到的bean对象
     */

    public T queryForOne(Connection conn ,String sql,Object...args){
        try {
            //实例化bean对象时bean变量名应和数据库中相同 否则应该在查询时使用别名
            return queryRunner.query(conn,sql,new BeanHandler<T>(clazz),args);
        } catch (SQLException throwables) {
            throw new RuntimeException(throwables);//此时将异常抛出(为了在事务操作出现异常时,能够检查到异常并同一回滚)
        }
        //此时不关闭conn 因为可能有事务存在  应该在事务执行完毕后统一关闭连接

    }

    /**
     * 多个查询
     * @param conn
     * @param sql
     * @param args
     * @return 返回查询到的bean对象集合
     */
    public List<T> queryForList(Connection conn,String sql,Object...args){
        try {
            return  queryRunner.query(conn,sql,new BeanListHandler<T>(clazz),args);
        } catch (SQLException throwables) {
            throw new RuntimeException(throwables);//此时将异常抛出(为了在事务操作出现异常时,能够检查到异常并同一回滚)
        }
        //此时不关闭conn 因为可能有事务存在  应该在事务执行完毕后统一关闭连接

    }

    /**
     * 执行返回一行一列的的SQL语句
     * @param conn
     * @param sql
     * @param args
     * @return
     */

    public Object queryForSingleValue(Connection conn,String sql,Object...args){

        try {
            return queryRunner.query(conn, sql, new ScalarHandler(), args);
        } catch (SQLException throwables) {
            throw new RuntimeException(throwables);//此时将异常抛出(为了在事务操作出现异常时,能够检查到异常并同一回滚)
        }
        //此时不关闭conn 因为可能有事务存在  应该在事务执行完毕后统一关闭连接

    }


}
